#ifndef _LINE_H_
#define _LINE_H_

/**
* @file line.h
* August 1, 2008
* 
* @brief Implementation of the LINE, a specialized curve object.
*
* This class derives the interface "Curve", implementing all the
* specific features of a LINE geometric object.
* 
* @author Antonio Miranda (amiranda@tecgraf.puc-rio.br )
* @author Andre Pereira (brabo@tecgraf.puc-rio.br)
* 
* @see Curve
* @see CurveFactory
*/

// includes
//----------

#include "curve.h"


// class definition
//------------------
class Line : public Curve
{
public:
   Line();
  ~Line();

  // get curve name
  void getName (char *name);


  void updateData( int dg, int nP, int nU, double* P, double* U );

  // get the key point of the curve
  vector<Point3D> getCurvePoints();

  // 
  vector<Point3D> getPolygonalPoints()
  { 
    return getCurvePoints();
  }

  // get points on Curve based on given number of subdivision and ratio
  void getSubdvision( int _n,
                      double _ratio,
                      vector<Point3D>& _subv );

  // get tangent vectors on Curve based on given number of subdivision and ratio
  void getTangent( int _nd,
                   double _ratio,
                   vector<Point3D>& _tang );

  // get the total length from the curve
  double getLength();

  // projects a given point in the curve. 
  int clstPoint( Point3D _pt,
                 double& _t,
                 Point3D& _pt_on,
                 double _tol );

  // given a parametric value t (0-1), it returns the coordinate and tangent of point
  void get3dPoint( double _t,
                   Point3D& _pt,
                   Point3D& _tg );

  // given a parametric value t (0-1), it returns the coordinates
  Point3D get3dPoint( double _t );

  // draw the curve using the object set in setDraw method
  void draw();

  // set the bound box of current curve
  void setBox();

  //////////////////////////////////////////////////////////////////////////
  /// Methods to add point to the curve
  //////////////////////////////////////////////////////////////////////////

  // begin add point - the application can insert an additional information
  //                   the each curve know how to deal
  int beginAddPoint( const vector<Point3D>& _addp );

  // add a point to the curve
  int addPoint( const Point3D& _pt );
  int addPoint( Point3D& _pt,
                double _tol );

  /** */
  void moveEndPoint( Point3D& _pt, double tol );

  // add a temporary point - using this method, the curve will be drawn
  void addTempPoint( Point3D& _pt );

  // same as above but used for orthogonal drawing
  void addTempOrthoPoint( Point3D& _pt );

  // gets last calculated temporary point
  Point3D getLastTempPoint( );

  // end add point and the curve is finally created
  int endAddPoint();

  // set end points
  void setEndPoints( Point3D _pt[2] );

  // get end points
  void getEndPoints( Point3D _pt[2] );

  //////////////////////////////////////////////////////////////////////////

  // delete the last point from the Curve
  void delPoint( Point3D& _pt );

  // try to delete a point in the curve
  void delPoint( Point3D& _pt, double _tol );

  // copy the current curve to another curve
  void copy( Curve** _cp );

  // transform the curve based on matrix transformation
  void transform( double _mt[4][4] );

  // invert points in the curve
  void invert();

  // check if the curve is possible
  int possible();

  // prints the coordinates of the points of the curve
  void print();

  //////////////////////////////////////////////////////////////////////////
  /// Methods to edit the curve
  //////////////////////////////////////////////////////////////////////////

  // these methods create curves the intersect to a plane
  // 1 - The plane is defined by a normal and d constant.
  int planeIntersect( Point3D& _n,
                     double _d, 
                     vector<Curve*>& _curves,
                     vector<Point3D>& _pts);
  // 2 - The plane is defined by an point on the plane and its normal.
  int planeIntersect( Point3D& _orig,
                     Point3D& _n, 
                     vector<Curve*>& _curves,
                     vector<Point3D>& _pts);

  // join the current curve with a given curve. The result is a third curve 
  int join( Curve* _givenCurve,
            Curve** _thirdCurve );

  // split the current curve based on its subdivision and ratio
  int split( vector<Curve*>& _curves );

  // split the current curve based on given subdivision and ratio
  int split( int _subdvision,
             double _ratio,
             vector<Curve*>& _curves );
  // extracts from the current curve another curve based on the given interval
  Curve* split( double _t0, double _t1, double _tol );

  /** */
  void setNumPoints( int n )
  {
    m_numPoints = n;
  }

  /** */
  void setP0( Point3D p )
  {
    m_p0 = p;
  }

  /** */
  void setP1( Point3D p )
  {
    m_p1 = p;
  }

  /** */
  void getP0( Point3D* p )
  {
    *p = m_p0;
  }

  /** */
  void getP1( Point3D* p )
  {
    *p = m_p1;
  }


private:
  // number of points (max has to be 2)
  int m_numPoints;

  // points that define the line segment
  Point3D m_p0;
  Point3D m_p1;

  void draw( Point3D& _pt );

};

#endif // _LINE_H_
